﻿using System.Threading;
using Cysharp.Threading.Tasks;
using FairyGUI;

namespace GameFramework.UI.FairyGUI
{
    public static class FairyGUIUtility
    {
        /// <summary>
        /// 异步创建GObject
        /// </summary>
        public static UniTask<GObject> CreateObjectAsync(string packageName, string componentName, CancellationToken cancellationToken)
        {
            return CreateObjectAsync(UIPackage.URL_PREFIX + packageName + "/" + componentName, cancellationToken);
        }
        
        /// <summary>
        /// 异步创建GObject
        /// </summary>
        public static async UniTask<GObject> CreateObjectAsync(string url, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
                return null;
            
            var completionSource = AutoResetUniTaskCompletionSource<GObject>.Create();
            var uniTask = completionSource.Task;
            
            UIPackage.CreateObjectFromURLAsync(url, o =>
            {
                completionSource.TrySetResult(o);
            });

            var gObject = await uniTask;
            
            await UniTask.SwitchToMainThread();
            
            if (gObject == null)
                return null;
            
            if (!cancellationToken.IsCancellationRequested)
                return gObject;
            
            gObject.Dispose();
            return null;
        }

        /// <summary>
        /// 从对象池中异步获取GObject
        /// </summary>
        public static async UniTask<GObject> CreateObjectAsync(this GObjectPool pool, string url, CancellationToken cancellationToken)
        {
            var gObject = pool.GetObjectFromPoolDirectly(url);
            if (gObject != null)
                return gObject;

            gObject = await CreateObjectAsync(url, CancellationToken.None);
            if (gObject == null)
                return null;
            
            if (!cancellationToken.IsCancellationRequested)
                return gObject;
            
            pool.ReturnObject(gObject);
            return null;
        }

        /// <summary>
        /// 将GObject尝试转成指定类型组件
        /// </summary>
        public static T asCom<T>(this GObject gObject) where T : GComponent
        {
            return gObject as T;
        }
        
        /// <summary>
        /// 获取事件发送者UI对象
        /// </summary>
        public static bool GetSenderObj(this EventContext eventContext, out GObject gObject)
        {
            gObject = eventContext.sender as GObject;
            return gObject != null;
        }

        /// <summary>
        /// 获取事件发送者UI组件
        /// </summary>
        public static bool GetSenderCom<T>(this EventContext eventContext, out T component) where T : GComponent
        {
            component = eventContext.sender as T;
            return component != null;
        }

        /// <summary>
        /// 获取事件数据UI对象
        /// </summary>
        public static bool GetDataObj(this EventContext eventContext, out GObject gObject)
        {
            gObject = eventContext.data as GObject;
            return gObject != null;
        }

        /// <summary>
        /// 获取事件数据UI组件
        /// </summary>
        public static bool GetDataCom<T>(this EventContext eventContext, out T component) where T : GComponent
        {
            component = eventContext.data as T;
            return component != null;
        }

        /// <summary>
        /// 通过列表项获取对应的列表下标
        /// </summary>
        public static int GetItemIndexByChild(this GList gList, GObject child)
        {
            return gList.ChildIndexToItemIndex(gList.GetChildIndex(child));
        }
    }
}